import os
import re
import datetime
from functools import reduce

from pathlib import Path
import pandas as pd
from pandas import DataFrame, Series
from datetime import datetime

# 中文字符宽度调整
pd.set_option('display.unicode.east_asian_width', True)
# 显示所有列
pd.set_option('display.max_columns', None)
# 显示所有行
pd.set_option('display.max_rows', None)
# 设置value的显示长度为100，默认为50
pd.set_option('max_colwidth', 100)

BASE_PATH_5G实训 = r"D:\100-Project\2024-2025-2学期安排\武昌首义学院\19101296_《5G生态应用技术实践（企业）》"


def check_filename_format(filename_list):
    """
    检查字符串列表中的每个字符串是否符合六部分格式

    参数:
    strings : 要检查的字符串列表

    输出:
    打印所有不符合规则的字符串
    """
    invalid_strings = []
    pattern = r'^[^-\.]+-[^-\.]+-[^-\.]+\.[^-\.]+\.[^-\.]+\.[^-\.]+$'

    for s in filename_list:
        if not bool(re.match(pattern, s)):
            invalid_strings.append(s)

    if invalid_strings:
        print("以下字符串不符合格式要求:")
        for s in invalid_strings:
            print(f"  - {s}")
        print(f"\n总计: {len(invalid_strings)} 个字符串不符合规则")
    else:
        print("所有字符串都符合格式要求!")


def get_files_name(folder_path, return_type="name_only") -> Series:
    """
    获得指定目录下的所有文件的名称
    返回:
        list: 包含所有 .docx 文件名的列表
    """
    try:
        # 验证文件夹是否存在
        if not os.path.isdir(folder_path):
            print(f"错误: 文件夹不存在 - {folder_path}")
            return pd.Series([], name='文件名')

        folder = Path(folder_path)
        docx_files = []

        iterator = folder.iterdir()

        # 收集所有 .docx 文件
        for item in iterator:
            if item.is_file() and (item.suffix.lower() == '.docx' or item.suffix.lower() == '.pdf'):
                # 根据返回类型处理路径
                if return_type == "full_path":
                    docx_files.append(str(item.absolute()))
                elif return_type == "name_only":
                    docx_files.append(item.name)
                elif return_type == "relative":
                    docx_files.append(str(item.relative_to(folder)))
                else:
                    docx_files.append(str(item.absolute()))

        # 按文件名排序
        docx_files.sort()

        print(f"在 {folder_path} 中找到 {len(docx_files)} 个文件")

        check_filename_format(docx_files)
        return pd.Series(docx_files, name='文件名')

    except Exception as e:
        print(f"获取文件列表时出错: {str(e)}")
        return pd.Series([], name='文件名')


def extract_parts_from_series(series, part_index):
    """
    从符合格式的字符串Series中提取指定部分

    参数:
    series : pandas Series, 包含格式为 "aaa-bbb-ccc.ddd.eee.fff" 的字符串
    part_index : 要提取的部分索引 (1-6)

    返回:
    pd.Series : 包含提取部分的Series

    异常:
    ValueError: 当part_index不在1-6范围内
    """
    # 验证部分索引
    if part_index < 1 or part_index > 6:
        raise ValueError("part_index 必须在 1 到 6 之间")

    # 编译高效的正则表达式
    pattern = re.compile(r'^([^-\.]+)-([^-\.]+)-([^-\.]+)\.([^-\.]+)\.([^-\.]+)\.([^-\.]+)$')

    # 提取函数
    def extract_part(s):
        match = pattern.match(s)
        if match:
            return match.group(part_index)
        return None  # 不符合格式的返回None

    # 应用提取函数并返回Series
    return series.apply(extract_part)


def find_duplicates(items: Series) -> bool:
    """查找并打印Series中的重复项"""
    # 计算每个值的出现次数
    value_counts = items.value_counts()

    # 找出重复项（出现次数大于1）
    duplicates = value_counts[value_counts > 1]

    if not duplicates.empty:
        print(f"列表中有 {len(duplicates)} 个重复项:")
        for i, (value, count) in enumerate(duplicates.items(), 1):
            print(f"{i}. {value} (出现次数: {count})")
        return True
    else:
        return False


def get_学号_segment(files_name: Series) -> Series:
    extracted = extract_parts_from_series(files_name, 2)
    if find_duplicates(extracted):
        exit(0)
    extracted.name = '学号'
    return extracted.astype(int)


def get_姓名_segment(files_name: Series) -> Series:
    extracted = extract_parts_from_series(files_name, 3)
    if find_duplicates(extracted):
        exit(0)
    extracted.name = '姓名'
    return extracted.astype(str)


def get_real_日期_segment(files_name: Series) -> Series:
    extracted = extract_parts_from_series(files_name, 4)
    extracted.name = '提交日期'
    return extracted.astype(str)


def get_logical_日期_segment(files_name: Series) -> Series:
    extracted = extract_parts_from_series(files_name, 5)
    return extracted.astype(str)


"""
def combine_series_to_dataframe(*series_list) -> DataFrame:
    return pd.concat(series_list, axis=1)
"""


def get_学生_信息() -> DataFrame:
    try:
        # 读取Excel文件中的指定列
        df = pd.read_excel(
            f"{BASE_PATH_5G实训}\\学生名单.xlsx",
            usecols=['学号', '姓名'],
            dtype={'学号': int, '姓名': str},
            header=0,
            converters={
                '学号': lambda x: int(x) if str(x).strip() not in ["N/A", ""] else 0,
            }
        )

        # 打印读取的信息
        print(f"✅ 成功读取文件: {BASE_PATH_5G实训}\学生名单.xlsx")
        # print(f"读取的列: {df.columns.tolist()} \t 总行数: {len(df)}")

        return df

    except Exception as e:
        print(f"❌ 读取失败: {str(e)}")
        raise


def add_year_prefix_enhanced(series: Series, year: str) -> Series:
    # 转换为字符串并验证格式
    str_series = series.astype(str)

    # 检查是否为四位数字
    mask = str_series.str.match(r'^\d{4}$')

    # 添加前缀
    result = year + str_series

    # 标记无效输入
    result[~mask] = "无效格式: " + str_series[~mask]

    return result


# 定义转换函数
def convert_single_date(yyyymmdd):
    try:
        # 提取月份和日期
        year = int(yyyymmdd[:4])
        month = int(yyyymmdd[4:6])
        day = int(yyyymmdd[6:])
        return datetime(year, month, day)
    except (ValueError, TypeError) as e:
        print(f"转换日期格式时出错: {str(e)}")
        # 处理无效格式
        return pd.NaT


def convert_mmdd_to_date(series) -> Series:
    yyyymmdd = add_year_prefix_enhanced(series, "2025")
    se_date = yyyymmdd.apply(convert_single_date)

    # 应用转换函数
    return se_date


def calculate_date_scores(se_date: Series, base_score=25) -> Series:
    """
    计算日期数组中每个日期的评分
    """

    # 1. 找到最早日期
    min_date = se_date.min()

    # 2. 计算每个日期与最早日期的天数差
    days_diff = (se_date - min_date).dt.days

    return base_score - (days_diff + 1) // 2


def merge_student_dataframes(*dfs):
    """
    合并多个包含学生数据的DataFrame

    参数:
    *dfs : 可变数量的DataFrame，每个DataFrame必须包含'学号'和'姓名'列

    返回:
    pd.DataFrame : 合并后的DataFrame，包含学号、姓名和所有科目列

    异常:
    ValueError: 如果输入少于两个DataFrame
    """
    if len(dfs) < 2:
        raise ValueError("至少需要两个DataFrame进行合并")

    # 1. 提取所有DataFrame中的科目列（排除学号和姓名）
    all_subject_columns = set()
    for df in dfs[1:]:  # 从第二个DataFrame开始
        subject_cols = [col for col in df.columns if col not in ['学号', '姓名']]
        all_subject_columns.update(subject_cols)

    # 2. 创建基础表（只保留学号和姓名）
    base_df = dfs[0][['学号', '姓名']].copy()

    # 3. 使用reduce函数逐步合并所有DataFrame
    def merge_func(left, right):
        # 从右侧DataFrame中提取学号和科目列
        right_subject_cols = [col for col in right.columns if col in all_subject_columns]
        right_subset = right[['学号'] + right_subject_cols]
        right_subset['学号'].astype(int)

        # 左连接合并
        return pd.merge(left, right_subset, on='学号', how='left')

    # 应用reduce进行逐步合并
    merged_df = reduce(merge_func, [base_df] + list(dfs[1:]))

    return merged_df


if __name__ == "__main__":
    se_files_name = get_files_name(f"{BASE_PATH_5G实训}\学生提交")
    # print(se_files_name)
    se_学号 = get_学号_segment(se_files_name)
    print(se_学号)
